
package edu.predatorwars.client;

import java.awt.Point;

import edu.predatorwars.client.visualization.VisualizationCallbackInterface;
import edu.predatorwars.client.visualization.VisualizationStarter;
import edu.predatorwars.shared.models.Board;
import edu.predatorwars.shared.models.Buff;
import edu.predatorwars.shared.models.Creature;
import edu.predatorwars.shared.models.GameInfo;
import edu.predatorwars.shared.models.Location;
import edu.predatorwars.shared.models.ModelUtility;
import edu.predatorwars.shared.models.Move;
import edu.predatorwars.shared.models.Resource;
import edu.predatorwars.shared.models.Terrain;
import edu.predatorwars.shared.models.Player;
import edu.predatorwars.shared.models.PlayerConnectionInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;

public class Client implements VisualizationCallbackInterface {
	
	
	private VisualizationStarter vs;
	private Client me;
	private Player myPlayer;
	
	private Player player1;
	private Player player2;
	
	private Resource resource1;
	private Resource resource2;
	private Resource resource3;
	private Resource resource4;
	private Resource resource5;
	
	private Location[][] locationArray;
	private Board board;
	
	
	//inGame indicates if the player is currently playing a game
	private boolean inGame = false;
	
	public boolean exit = false;
	
	Queue<Runnable> clientWork = new ConcurrentLinkedQueue<Runnable>();
	
	public static void main(String[] args) {
		new Client();
	}
	
	public Client() {
		//startBoard();
		startSelection();
	}
	
	public void startSelection() {
		vs = new VisualizationStarter(this, "Predator Wars:  The Animal Insurrection");
		List<GameInfo> games = new ArrayList<GameInfo>();
		GameInfo gi1 = new GameInfo(new UUID(1023,1231),44,11,"Game Name #1");
		GameInfo gi2 = new GameInfo(new UUID(1024,1231),44,11,"Game Name #2");
		GameInfo gi3 = new GameInfo(new UUID(1023,1431),44,11,"Game Name #3");
		games.add(gi1);
		games.add(gi2);
		games.add(gi3);
		games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);games.add(gi1);
		vs.setGames(games);
		Map<Integer, Float> stat1 = new HashMap<Integer, Float>();
		stat1.put(Creature.STAT_HEALTH, 50f);
		stat1.put(Creature.STAT_MAX_HEALTH, 50f);
		stat1.put(Creature.STAT_ARMOR, 20f);
		stat1.put(Creature.STAT_STRENGTH, 5f);
		stat1.put(Creature.STAT_SIGHT, 10f);
		stat1.put(Creature.STAT_SPEED, 15f);
		Map<Integer, Float> stat2 = new HashMap<Integer, Float>();
		stat2.put(Creature.STAT_HEALTH, 100f);
		stat2.put(Creature.STAT_MAX_HEALTH, 100f);
		stat2.put(Creature.STAT_ARMOR, 5f);
		stat2.put(Creature.STAT_STRENGTH, 15f);
		stat2.put(Creature.STAT_SIGHT, 7f);
		stat2.put(Creature.STAT_SPEED, 25f);
		Map<Integer, Float> stat3 = new HashMap<Integer, Float>();
		stat3.put(Creature.STAT_HEALTH, 10f);
		stat3.put(Creature.STAT_MAX_HEALTH, 10f);
		stat3.put(Creature.STAT_ARMOR, 120f);
		stat3.put(Creature.STAT_STRENGTH, 1f);
		stat3.put(Creature.STAT_SIGHT, 1f);
		stat3.put(Creature.STAT_SPEED, 150f);
		Map<Integer, Float> stat4 = new HashMap<Integer, Float>();
		stat4.put(Creature.STAT_HEALTH, 150f);
		stat4.put(Creature.STAT_MAX_HEALTH, 150f);
		stat4.put(Creature.STAT_ARMOR, 220f);
		stat4.put(Creature.STAT_STRENGTH, 50f);
		stat4.put(Creature.STAT_SIGHT, 120f);
		stat4.put(Creature.STAT_SPEED, 135f);
		Map<Integer, Float> stat5 = new HashMap<Integer, Float>();
		stat5.put(Creature.STAT_HEALTH, 510f);
		stat5.put(Creature.STAT_MAX_HEALTH, 510f);
		stat5.put(Creature.STAT_ARMOR, 20f);
		stat5.put(Creature.STAT_STRENGTH, 5f);
		stat5.put(Creature.STAT_SIGHT, 10f);
		stat5.put(Creature.STAT_SPEED, 105f);
		Creature c1 = new Creature(Creature.TYPE_BEAR, stat1);
		Creature c2 = new Creature(Creature.TYPE_ELEPHANT, stat2);
		Creature c3 = new Creature(Creature.TYPE_GORILLA, stat3);
		Creature c4 = new Creature(Creature.TYPE_SNAKE, stat4);
		Creature c5 = new Creature(Creature.TYPE_WOLF, stat5);
		ArrayList<Creature> creatures = new ArrayList<Creature>();
		creatures.add(c1); creatures.add(c2);creatures.add(c3);creatures.add(c4);creatures.add(c5);
		vs.setCreatures(creatures);
		
		waiting();
	}
	
	
	public void waiting() {
		while (!exit) {
			Runnable toRun;
			synchronized(clientWork) {
				while (clientWork.size() == 0) {
				try {clientWork.wait();} catch (InterruptedException e) {e.printStackTrace();}
				}
				toRun = clientWork.poll();
			}
			toRun.run();
		}
	}
	
	public void startBoard() {
		
		/*3600 hex squares - 120 fps T9900 + 260m*/
		locationArray = new Location[40][40];
		for (int i=0;i< locationArray.length;i++ ) {
			for (int j =0; j< locationArray[i].length;j++) {
				switch( (int) (Math.random() * 4d)) {
					case 0:	locationArray[i][j] = new Location(Terrain.EMPTY,true,false, false); break;
					case 1: locationArray[i][j] = new Location(Terrain.WATER,true, false, false); break;
					case 2:	locationArray[i][j] = new Location(Terrain.GRASS,true, false, false); break;
					case 3:	locationArray[i][j] = new Location(Terrain.MOUNTAIN,true, false, false); break;
				}
			}
		}
		
		board = new Board("test", locationArray,0);

		
		player1 = new Player(new PlayerConnectionInfo("Test", "127.0.0.5"));
		player2 = new Player(new PlayerConnectionInfo("Test2","127.0.0.1"));
		
		resource1 = new Resource(Resource.RAM,"Horns of the Ram",new Buff[] {new Buff(Creature.STAT_HEALTH,1,10)});
		resource2 = new Resource(Resource.HAWK, "Eye of the Hawk", new Buff[] {new Buff(Creature.STAT_HEALTH,1,10)});
		resource3 = new Resource(Resource.RABBIT, "Foot of the Rabbit",new Buff[] {new Buff(Creature.STAT_HEALTH,1,10)});
		resource4 = new Resource(Resource.TURTLE, "Shell of the Turtle",new Buff[] {new Buff(Creature.STAT_HEALTH,1,10)});
		resource5 = new Resource(Resource.WATER, "Fresh Water",new Buff[] {new Buff(Creature.STAT_HEALTH,1,10)});
		
		player1.setColor(0.5f, 0.25f, 0.35f);
		HashMap<Integer, Float> stats1 = new HashMap<Integer, Float>();
		stats1.put(Creature.STAT_ARMOR, 14f);
		stats1.put(Creature.STAT_HEALTH, 100f);
		stats1.put(Creature.STAT_MAX_HEALTH, 200f);
		stats1.put(Creature.STAT_SIGHT, 4f);
		stats1.put(Creature.STAT_STRENGTH, 1f);
		stats1.put(Creature.STAT_SPEED, 2f);
		
		HashMap<Integer, Float> stats2 = new HashMap<Integer, Float>();
		stats2.put(Creature.STAT_ARMOR, 24f);
		stats2.put(Creature.STAT_HEALTH, 200f);
		stats2.put(Creature.STAT_MAX_HEALTH, 400f);
		stats2.put(Creature.STAT_SIGHT, 1f);
		stats2.put(Creature.STAT_STRENGTH, 2f);
		stats2.put(Creature.STAT_SPEED, 1f);
		
		player1.setCreature(new Creature(Creature.TYPE_SNAKE, stats1));// (int) (Math.random() * 5), stats1));
		player1.getCreature().addBuff(new Buff(Creature.STAT_ARMOR, 14f, 0));
		
		myPlayer = player1;
		
		locationArray[3][3].setPlayer(player1);
		locationArray[3][4].setResource(resource1);
		
		player2.setColor((float)Math.random(), (float)Math.random(), (float)Math.random());
		player2.setCreature(new Creature( (int) (Math.random() * 5), stats2));
		locationArray[0][15].setPlayer(player2);
		
		
		
		vs = new VisualizationStarter(this, "Predator Wars:  The Animal Insurrection");
		vs.setBoard(locationArray);
		List<Move> moves = new ArrayList<Move>();
		moves.add(new Move(0,0));
		moves.add(new Move(0,1));
		moves.add(new Move(1,0));
		vs.setMoves(moves);
		vs.setTurnsLeft(turnsleft);
		vs.setMyPlayer(player1);
		
		test4();
		
		System.out.println("done");
	}
	
	
	public void postRunnable(Runnable run) {
		synchronized(clientWork) {
			clientWork.offer(run);
			clientWork.notify();
		}
	}
	
	//test resources
	private void test4() {
		for (int i=0;i<10;i++) {
			vs.setBoard(locationArray);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			locationArray[3][4].setResource(resource5);
			vs.setBoard(locationArray);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			locationArray[3][4].setResource(resource2);
			vs.setBoard(locationArray);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			locationArray[3][4].setResource(resource3);
			vs.setBoard(locationArray);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			locationArray[3][4].setResource(resource4);
			vs.setBoard(locationArray);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			locationArray[3][5].setResource(resource5);
			vs.setBoard(locationArray);
		}
	}
	
	private int turnsleft = 9;
	//test move system
	private void test3() {
		while (!exit) {
			Runnable toRun;
			synchronized(clientWork) {
				while (clientWork.size() == 0) {
				try {clientWork.wait();} catch (InterruptedException e) {e.printStackTrace();}
				}
				toRun = clientWork.poll();
			}
			player1.getCreature().setHealth(player1.getCreature().getStat(Creature.STAT_HEALTH)-5);
			player2.getCreature().setHealth(player2.getCreature().getStat(Creature.STAT_HEALTH)-5);
			if (--turnsleft == 0) {
				turnsleft = 9;	
				vs.showMyTurn(true);
			}
			vs.setTurnsLeft(turnsleft);
			toRun.run();
		}
	}
	
	
	//test terrain swapping
	private void test2() {

		for (int z=0; z< 200;z++) {
		//vs.setBoard(locationArray);
		synchronized(this){
			try {
				this.wait(100);
				locationArray = new Location[40][40];
				for (int i=0;i< locationArray.length;i++ ) {
					for (int j =0; j< locationArray[i].length;j++) {
						switch( (int) (Math.random() * 4d)) {
							case 0:	locationArray[i][j] = new Location(Terrain.EMPTY,true,false, false); break;
							case 1: locationArray[i][j] = new Location(Terrain.WATER,true, false, false); break;
							case 2:	locationArray[i][j] = new Location(Terrain.GRASS,true, false, false); break;
							case 3: locationArray[i][j] = new Location(Terrain.MOUNTAIN, true, false, false); break;
						}
					}
				}
				vs.setBoard(locationArray);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
	
	//test player movements
	private void test1() {
		/*try moving player piece*/
		int a=3,b=3;/*
		for (;b<20;b++) {
			locationArray[a][b-1].setPlayer(null);
			locationArray[a][b].setPlayer(player1);
			synchronized(this) {
				try {
					this.wait(500);
				}
				catch (Exception e) {}
			}
			vs.setBoard(locationArray);
		}*/
		
		for (;b<20;) {
			b++;
			locationArray[a][b-1].setPlayer(null);
			locationArray[a][b].setPlayer(player1);
			synchronized(this) {
				try {
					this.wait(500);
				}
				catch (Exception e) {}
			}
			vs.setBoard(locationArray);
		}
		//
		for (;a<20;){
			a++;
			locationArray[a-1][b].setPlayer(null);
			locationArray[a][b].setPlayer(player1);
			synchronized(this) {
				try {
					this.wait(500);
				}
				catch (Exception e) {}
			}
			vs.setBoard(locationArray);
		}
		for (;b>0;) {
			b--;
			locationArray[a][b+1].setPlayer(null);
			locationArray[a][b].setPlayer(player1);
			synchronized(this) {
				try {
					this.wait(500);
				}
				catch (Exception e) {}
			}
			vs.setBoard(locationArray);
		}
		for (;a>0;){
			a--;
			locationArray[a+1][b].setPlayer(null);
			locationArray[a][b].setPlayer(player1);
			synchronized(this) {
				try {
					this.wait(500);
				}
				catch (Exception e) {}
			}
			vs.setBoard(locationArray);
		}
	}

	@Override
	public void chosenGame(UUID gameID) {
		System.out.println("User selected UUID: " + gameID );
	}


	@Override
	public void chosenAnimal(Creature animal) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public void exitGame() {
		System.out.println("user exited game");
	}

	@Override
	public void endedTurn() {
		System.out.println("user ended turn");
	}
	
	@Override
	public void moved(Point location) {
		// TODO Auto-generated method stub
		
		Point p = ModelUtility.getPosition(board, player1);
		locationArray[p.x][p.y].setPlayer(null);
		locationArray[location.x][location.y].setPlayer(player1);
		List<Move> moves = new ArrayList<Move>();
		moves.add(new Move(location.x+1, location.y+1));
		moves.add(new Move(location.x-1, location.y-1));
		moves.add(new Move(location.x+1, location.y));
		moves.add(new Move(location.x-1, location.y));
		moves.add(new Move(location.x, location.y+1));
		moves.add(new Move(location.x, location.y-1));
		vs.setBoard(locationArray);
		vs.setMoves(moves);
	}
	
	@Override
	public void confirmedModalDialog() {
		System.out.println("Dialog confirmed");
		vs.showMyTurn(false);
	}

	@Override
	public void createGame(String mapName, int maxPlayers) {
		System.out.println("user attempted to create game: " + mapName);
	}
}